package utils

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
)

const (
	FILE_MODE  = 0666
	DIR_MODE   = 0777
	DEBUG_MODE = false
)

func DebugPrint(args ...interface{}) (err error) {
	if DEBUG_MODE && len(args) > 0 {
		_, err = fmt.Fprintln(os.Stdout, args...)
	}
	return
}

func GetCurrDir() string {
	exePath, _ := os.Executable()
	return filepath.Dir(exePath)
}

func CreateFile(path string, mode os.FileMode) (fp *os.File, err error) {
	// create dirs if file not exists
	if dir := filepath.Dir(path); dir != "." {
		err = os.MkdirAll(dir, DIR_MODE)
	}
	if err == nil {
		fp, err = os.Create(path)
		if err == nil && mode != 0666 {
			fp.Chmod(mode)
		}
	}
	return
}

func OpenFile(path string) (fp *os.File, size int64, err error) {
	var info os.FileInfo
	// detect if file exists
	info, err = os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			fp, err = CreateFile(path, FILE_MODE)
		}
		return
	}
	size = info.Size()
	if size > 0 {
		fp, err = os.Open(path)
	} else {
		fp, err = os.OpenFile(path, os.O_RDWR, FILE_MODE)
	}
	return
}

func ReadBytes(fp *os.File, offset int64, size int) ([]byte, error) {
	chunk := make([]byte, size)
	_, err := fp.ReadAt(chunk, offset)
	return chunk, err
}

func ReadMoreBytes(fp *os.File, offset int64, sizes ...int) (data [][]byte, err error) {
	var n int
	for _, size := range sizes {
		chunk := make([]byte, size)
		n, err = fp.ReadAt(chunk, offset)
		if n > 0 {
			data = append(data, chunk[:n])
			offset += int64(size)
		}
		if err != nil {
			return
		}
	}
	return
}

func ReadLines(r io.Reader) ([]string, error) {
	var lines []string
	scanner := bufio.NewScanner(r)
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

func ReadCsv(r io.Reader, sep string, parts int) (int, [][]string, error) {
	var lines [][]string
	scanner := bufio.NewScanner(r)
	scanner.Split(bufio.ScanLines)
	maxCols := 0
	for scanner.Scan() {
		pieces := strings.SplitN(scanner.Text(), sep, parts)
		if len(pieces) > maxCols {
			maxCols = len(pieces)
		}
		lines = append(lines, pieces)
	}
	return maxCols, lines, scanner.Err()
}

func IgnoreLine(line []string, minCols int) bool {
	if minCols > 0 && len(line) < minCols {
		return true // 列数不足
	}
	if len(line) == 1 {
		word := strings.TrimSpace(line[0])
		if word == "" || strings.HasPrefix(word, "#") {
			return true // 空行或注释行
		}
	}
	return false
}
